﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace Algobox.JuicyLib.Collections.Generics
{
    public class SyncList<T> : IList<T>
    {
        /// <summary>
        /// Initializes a new instance of the System.Collections.Generic.List class that is empty and has the default initial capacity.
        /// </summary>
        public SyncList()
        {
            m_List = new List<T>();
        }
        /// <summary>
        /// Initializes a new instance of the System.Collections.Generic.List class that contains elements copied from the specified collection and has sufficient capacity to accommodate the number of elements copied.
        /// </summary>
        /// <param name="collection">The collection whose elements are copied to the new list.</param>
        /// <exception cref="System.ArgumentNullException">collection is null</exception>
        public SyncList(IEnumerable<T> collection)
        {
            m_List = new List<T>();
        }
        /// <summary>
        /// Initializes a new instance of the System.Collections.Generic.List class that is empty and has the specified initial capacity.
        /// </summary>
        /// <param name="capacity">The number of elements that the new list can initially store.</param>
        /// <exception cref="System.ArgumentOutOfRangeException">capacity is less than 0</exception>
        public SyncList(int capacity)
        {
            m_List = new List<T>();
        }

        ReaderWriterLockSlim m_Lock = new ReaderWriterLockSlim();
        List<T> m_List;

        #region IList<T> Members

        public int IndexOf(T item)
        {
            m_Lock.EnterReadLock();
            int result = m_List.IndexOf(item);
            m_Lock.ExitReadLock();
            return result;
        }

        public int IndexOf(T item, int index)
        {
            m_Lock.EnterReadLock();
            try
            {
                return m_List.IndexOf(item, index);
            }
            finally
            {
                m_Lock.ExitReadLock();
            }
        }

        public int IndexOf(T item, int index, int count)
        {
            m_Lock.EnterReadLock();
            try
            {
                return m_List.IndexOf(item, index, count);
            }
            finally
            {
                m_Lock.ExitReadLock();
            }
        }

        public void Insert(int index, T item)
        {
            m_Lock.EnterWriteLock();
            m_List.Insert(index, item);
            m_Lock.ExitWriteLock();
        }

        public void RemoveAt(int index)
        {
            m_Lock.EnterWriteLock();
            m_List.RemoveAt(index);
            m_Lock.ExitWriteLock();
        }

        public T this[int index]
        {
            get
            {
                m_Lock.EnterReadLock();
                try
                {
                    return m_List[index];
                }
                finally
                {
                    m_Lock.ExitReadLock();
                }
            }
            set
            {
                m_Lock.EnterWriteLock();
                try
                {
                    m_List[index] = value;
                }
                finally
                {
                    m_Lock.ExitWriteLock();
                }
            }
        }

        #endregion

        #region ICollection<T> Members

        public void Add(T item)
        {
            m_Lock.EnterWriteLock();
            m_List.Add(item);
            m_Lock.ExitWriteLock();
        }

        public void Clear()
        {
            m_Lock.EnterWriteLock();
            m_List.Clear();
            m_Lock.ExitWriteLock();
        }

        public bool Contains(T item)
        {
            m_Lock.EnterReadLock();
            bool result = m_List.Contains(item);
            m_Lock.ExitReadLock();
            return result;
        }

        public void CopyTo(T[] array, int arrayIndex)
        {
            m_Lock.EnterWriteLock();
            m_List.CopyTo(array, arrayIndex);
            m_Lock.ExitWriteLock();
        }

        public int Count
        {
            get
            {
                m_Lock.EnterReadLock();
                int result = m_List.Count;
                m_Lock.ExitReadLock();
                return result;
            }
        }

        public bool IsReadOnly
        {
            get
            {
                m_Lock.EnterReadLock();
                bool result = ((ICollection<T>)m_List).IsReadOnly;
                m_Lock.ExitReadLock();
                return result;
            }
        }

        public bool Remove(T item)
        {
            m_Lock.EnterWriteLock();
            bool result = m_List.Remove(item);
            m_Lock.ExitWriteLock();
            return result;
        }

        #endregion

        #region IEnumerable<T> Members

        public IEnumerator<T> GetEnumerator()
        {
            m_Lock.EnterReadLock();
            try
            {
                return ((IEnumerable<T>)m_List).GetEnumerator();
            }
            finally
            {
                m_Lock.ExitReadLock();
            }
        }

        #endregion

        #region IEnumerable Members

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            m_Lock.EnterReadLock();
            try
            {
                return m_List.GetEnumerator();
            }
            finally
            {
                m_Lock.ExitReadLock();
            }
        }

        #endregion
    }
}
